package lg.minecraft.plugin.cobblemoncore.util;

import com.cobblemon.mod.common.api.abilities.AbilityTemplate;
import com.cobblemon.mod.common.api.moves.Move;
import com.cobblemon.mod.common.api.moves.MoveTemplate;
import com.cobblemon.mod.common.api.types.ElementalType;
import com.cobblemon.mod.common.pokeball.PokeBall;
import com.cobblemon.mod.common.pokemon.Gender;
import com.cobblemon.mod.common.pokemon.Nature;
import com.cobblemon.mod.common.pokemon.Species;
import lg.minecraft.plugin.cobblemoncore.LGCobblemonCore;
import lg.minecraft.plugin.cobblemoncore.config.mapping.*;
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @author langle__
 * @version 1.0
 */
public class PokemonDataCache {

    private static PokemonDataCache instance;

    private final SpeciesMapping speciesMapping = new SpeciesMapping();
    private final MoveMapping moveMapping = new MoveMapping();
    private final ElementalTypeMapping elementalTypeMapping = new ElementalTypeMapping();
    private final PokeBallMapping pokeBallMapping = new PokeBallMapping();
    private final AbilityMapping abilityMapping = new AbilityMapping();
    private final NatureMapping natureMapping = new NatureMapping();
    private final GenderMapping genderMapping = new GenderMapping();

    private Map<String, Species> speciesMap;
    private Map<String, PokeBall> pokeBallMap;
    private Map<String, Nature> natureMap;
    private Map<String, AbilityTemplate> abilityTemplateMap;
    private Map<String, MoveTemplate> moveMap;
    private Map<String, ElementalType> elementalTypeMap;
    private Map<String, Gender> genderMap;

    private Map<Species, String> speciesReverseMap;
    private Map<PokeBall, String> pokeBallReverseMap;
    private Map<Nature, String> natureReverseMap;
    private Map<AbilityTemplate, String> abilityReverseMap;
    private Map<MoveTemplate, String> moveReverseMap;
    private Map<ElementalType, String> elementalTypeReverseMap;
    private Map<Gender, String> genderReverseMap;

    private PokemonDataCache() {}

    public static PokemonDataCache getInstance() {
        if (instance == null) {
            instance = new PokemonDataCache();
        }
        return instance;
    }

    public void loadData() {
        speciesMapping.load();
        moveMapping.load();
        elementalTypeMapping.load();
        pokeBallMapping.load();
        abilityMapping.load();
        natureMapping.load();
        genderMapping.load();

        speciesMap = speciesMapping.getMapping();
        pokeBallMap = pokeBallMapping.getMapping();
        natureMap = natureMapping.getMapping();
        abilityTemplateMap = abilityMapping.getMapping();
        moveMap = moveMapping.getMapping();
        elementalTypeMap = elementalTypeMapping.getMapping();
        genderMap = genderMapping.getMapping();

        speciesReverseMap = speciesMapping.getReverse();
        pokeBallReverseMap = pokeBallMapping.getReverse();
        natureReverseMap = natureMapping.getReverse();
        abilityReverseMap = abilityMapping.getReverse();
        moveReverseMap = moveMapping.getReverse();
        elementalTypeReverseMap = elementalTypeMapping.getReverse();
        genderReverseMap = genderMapping.getReverse();
    }

    /**
     * 通过键获取对应的物种对象。
     *
     * @param key 物种的键
     * @return 对应的 Species 对象，如果不存在则返回 null
     */
    public Species getSpeciesByKey(String key) {
        return speciesMap.get(key);
    }

    /**
     * 通过物种对象查找对应的键。
     *
     * @param species 物种对象
     * @return 对应的键，如果不存在则返回 null
     */
    @Nullable
    public String findSpeciesKey(Species species) {
        return speciesReverseMap.get(species);
    }

    /**
     * 通过键获取对应的精灵球对象。
     *
     * @param key 精灵球的键
     * @return 对应的 PokeBall 对象，如果不存在则返回 null
     */
    public PokeBall getPokeBallByKey(String key) {
        return pokeBallMap.get(key);
    }

    /**
     * 通过精灵球对象查找对应的键。
     *
     * @param pokeBall 精灵球对象
     * @return 对应的键，如果不存在则返回 null
     */
    public String findPokeBallKey(PokeBall pokeBall) {
        return pokeBallReverseMap.get(pokeBall);
    }

    /**
     * 通过键获取对应的性格对象。
     *
     * @param key 性格的键
     * @return 对应的 Nature 对象，如果不存在则返回 null
     */
    public Nature getNatureByKey(String key) {
        return natureMap.get(key);
    }

    /**
     * 通过性格对象查找对应的键。
     *
     * @param nature 性格对象
     * @return 对应的键，如果不存在则返回 null
     */
    public String findNatureKey(Nature nature) {
        return natureReverseMap.get(nature);
    }

    /**
     * 通过键获取对应的能力模板对象。
     *
     * @param key 能力模板的键
     * @return 对应的 AbilityTemplate 对象，如果不存在则返回 null
     */
    public AbilityTemplate getAbilityByKey(String key) {
        return abilityTemplateMap.get(key);
    }

    /**
     * 通过能力模板对象查找对应的键。
     *
     * @param abilityTemplate 能力模板对象
     * @return 对应的键，如果不存在则返回 null
     */
    public String findAbilityKey(AbilityTemplate abilityTemplate) {
        return abilityReverseMap.get(abilityTemplate);
    }

    /**
     * 通过键获取对应的招式模板对象。
     *
     * @param key 招式模板的键
     * @return 对应的 MoveTemplate 对象，如果不存在则返回 null
     */
    public MoveTemplate getMoveByKey(String key) {
        return moveMap.get(key);
    }

    /**
     * 通过招式模板对象查找对应的键。
     *
     * @param moveTemplate 招式模板对象
     * @return 对应的键，如果不存在则返回 null
     */
    public String findMoveKey(MoveTemplate moveTemplate) {
        return moveReverseMap.get(moveTemplate);
    }

    public String findMoveKey(Move move) {
        return moveReverseMap.get(move.getTemplate());
    }

    /**
     * 通过键获取对应的属性类型对象。
     *
     * @param key 属性类型的键
     * @return 对应的 ElementalType 对象，如果不存在则返回 null
     */
    public ElementalType getElementalTypeByKey(String key) {
        return elementalTypeMap.get(key);
    }

    /**
     * 通过属性类型对象查找对应的键。
     *
     * @param elementalType 属性类型对象
     * @return 对应的键，如果不存在则返回 null
     */
    public String findElementalTypeKey(ElementalType elementalType) {
        return elementalTypeReverseMap.get(elementalType);
    }

    /**
     * 通过键获取对应的性别对象。
     *
     * @param key 性别的键
     * @return 对应的 Gender 对象，如果不存在则返回 null
     */
    public Gender getGenderByKey(String key) {
        return genderMap.get(key);
    }

    /**
     * 通过性别对象查找对应的键。
     *
     * @param gender 性别对象
     * @return 对应的键，如果不存在则返回 null
     */
    public String findGenderKey(Gender gender) {
        return genderReverseMap.get(gender);
    }

    /**
     * 获取物种映射的键集合。
     *
     * @return 物种映射的键集合
     */
    public Set<String> getSpeciesKeySet() {
        return speciesMap.keySet();
    }

    /**
     * 获取精灵球映射的键集合。
     *
     * @return 精灵球映射的键集合
     */
    public Set<String> getPokeBallKeySet() {
        return pokeBallMap.keySet();
    }

    /**
     * 获取性格映射的键集合。
     *
     * @return 性格映射的键集合
     */
    public Set<String> getNatureKeySet() {
        return natureMap.keySet();
    }

    /**
     * 获取能力模板映射的键集合。
     *
     * @return 能力模板映射的键集合
     */
    public Set<String> getAbilityKeySet() {
        return abilityTemplateMap.keySet();
    }

    /**
     * 获取招式模板映射的键集合。
     *
     * @return 招式模板映射的键集合
     */
    public Set<String> getMoveKeySet() {
        return moveMap.keySet();
    }

    /**
     * 获取属性类型映射的键集合。
     *
     * @return 属性类型映射的键集合
     */
    public Set<String> getElementalTypeKeySet() {
        return elementalTypeMap.keySet();
    }

    /**
     * 获取性别映射的键集合。
     *
     * @return 性别映射的键集合
     */
    public Set<String> getGenderKeySet() {
        return genderMap.keySet();
    }

    /**
     * 获取物种映射的键集合。
     *
     * @return 物种映射的键集合
     */
    public List<String> getSpeciesKeyList() {
        return new ArrayList<>(speciesReverseMap.values());
    }

    /**
     * 获取精灵球映射的键集合。
     *
     * @return 精灵球映射的键集合
     */
    public List<String> getPokeBallKeyList() {
        return new ArrayList<>(pokeBallReverseMap.values());
    }

    /**
     * 获取性格映射的键集合。
     *
     * @return 性格映射的键集合
     */
    public List<String> getNatureKeyList() {
        return new ArrayList<>(natureReverseMap.values());
    }

    /**
     * 获取能力模板映射的键集合。
     *
     * @return 能力模板映射的键集合
     */
    public List<String> getAbilityKeyList() {
        return new ArrayList<>(abilityReverseMap.values());
    }

    /**
     * 获取招式模板映射的键集合。
     *
     * @return 招式模板映射的键集合
     */
    public List<String> getMoveKeyList() {
        return new ArrayList<>(moveReverseMap.values());
    }

    /**
     * 获取属性类型映射的键集合。
     *
     * @return 属性类型映射的键集合
     */
    public List<String> getElementalTypeKeyList() {
        return new ArrayList<>(elementalTypeReverseMap.values());
    }

    /**
     * 获取性别映射的键集合。
     *
     * @return 性别映射的键集合
     */
    public List<String> getGenderKeyList() {
        return new ArrayList<>(genderReverseMap.values());
    }

    // 末尾方法 其他类型

    /**
     * 获取技能的名称。
     *
     * @param name 技能的名称
     * @return 技能的名称，如果不存在则返回 null
     */
    public String getMoveName(String name) {
        MoveTemplate move = moveMap.get(name);
        return move == null ? null : move.getName();
    }

    /**
     * 获取能力的名称。
     *
     * @param name 能力的名称
     * @return 能力的名称，如果不存在则返回 null
     */
    public String getAbilityName(String name) {
        AbilityTemplate abilityTemplate = abilityTemplateMap.get(name);
        return abilityTemplate == null ? null : abilityTemplate.getName();
    }

    /**
     * 获取元素类型的名称。
     *
     * @param name 元素类型的名称
     * @return 元素类型的名称，如果不存在则返回 null
     */
    public String getElementalTypeName(String name) {
        ElementalType elementalType = elementalTypeMap.get(name);
        return elementalType == null ? null : elementalType.getName();
    }

    /**
     * 获取属性的名称。
     *
     * @param name 属性的名称
     * @return 属性的名称，如果不存在则返回 null
     */
    public String getNatureName(String name) {
        Nature nature = natureMap.get(name);
        return nature == null ? null : nature.getName().toString();
    }

    /**
     * 获取精灵球的简化名称。
     *
     * @param name 精灵球的名称
     * @return 简化后的精灵球名称，如果不存在则返回 null
     */
    public String getPokeBallName(String name) {
        PokeBall pokeBall = pokeBallMap.get(name);
        return pokeBall == null ? null : LGCobblemonCore.simplify(pokeBall.getName());
    }

    /**
     * 获取性别的名称。
     *
     * @param name 性别的名称
     * @return 性别的名称，如果不存在则返回 null
     */
    public String getGenderName(String name) {
        Gender gender = genderMap.get(name);
        return gender == null ? null : gender.name();
    }

}